#ifndef XMEN_SM2_INTERNAL_H
#define XMEN_SM2_INTERNAL_H

#include "EasyXMen_sm2.h"
/*------------------------------Macro------------------------------*/
/*CPU endian.*/
#if (CPU_ENDIAN_TYPE == CPU_LITTLE_ENDIAN)
#define BYTE_BOT 0
#define BYTE_TOP 1
#else
#define BYTE_BOT 1
#define BYTE_TOP 0
#endif

#define XMEN_IBITS 32 /* bits in int  */
#define XMEN_MSBIT ((unsigned int)1 << (XMEN_IBITS - 1))
#define XMEN_TOOBIG (1 << (XMEN_IBITS - 2))

#define XMEN_OBITS (XMEN_MSBIT - 1)

#define XMEN_LBITS 32 /* bits in long */
#define XMEN_FLASH 52
#define XMEN_MAXDEPTH 24
#define MIRACL 32
#define MAXBASE ((XMen_SmallType)1 << (MIRACL - 1))

#define XMEN_OUT
#define XMEN_IN(N)

#ifdef XMEN_STATIC
#define XMEN_DEFAULT_BUFFER_SIZE 260
#else
#define XMEN_DEFAULT_BUFFER_SIZE 1024
#endif

/* The size of the bigs and elliptic curve points allocated for stack or heap memory. */
#define XMEN_ROUNDUP(a, b) ((a) - 1) / (b) + 1
#define XMEN_SL sizeof(long)

/* Convert uppercase size to the size of the desired structure. */
#define xmen_size(n) (((sizeof(struct bigtype) + ((n) + 2) * sizeof(int)) - 1) / XMEN_SL + 1) * XMEN_SL
#define xmen_big_reserve(n, m) ((n) * xmen_size(m) + XMEN_SL)
#define xmen_esize_a(n) (((sizeof(XMen_ECurvePointT) + xmen_big_reserve(2, (n))) - 1) / XMEN_SL + 1) * XMEN_SL
#define xmen_esize(n) (((sizeof(XMen_ECurvePointT) + xmen_big_reserve(3, (n))) - 1) / XMEN_SL + 1) * XMEN_SL
#define xmen_ecp_reserve_a(n, m) ((n) * xmen_esize_a(m) + XMEN_SL)
#define xmen_ecp_reserve(n, m) ((n) * xmen_esize(m) + XMEN_SL)

#define XMEN_TOBYTE(x) ((unsigned char)(x))

#define XMEN_DIV(a, b) ((a) / (b))
#define XMEN_REMAIN(a, b) ((a) % (b))
#define XMEN_LROUND(a) ((a))

#ifdef XMEN_FLASH
/* no of Bits per double exponent */
#define XMEN_EBITS (8 * sizeof(double) - XMEN_FLASH)
#define XMEN_BTS 16
#define XMEN_MSK 0xFFFF
#endif /*XMEN_FLASH*/

#ifdef XMEN_FLASH
#define XMEN_SPACES 28
#else
#define XMEN_SPACES 27
#endif

#define XMEN_ECC_STORE_N 8 /* 8/9 is close to optimal for 256 bit exponents */
#define XMEN_ECC_STORE_2M 9
#define XMEN_ECC_STORE_N2 8

/*If multiple addition has m points and requires s precomputed values, then this is the maximum value of m * s*/
#define XMEN_MAX_M_T_S 64

/*------------------------------Data Type------------------------------*/
#define XMen_DltType long long
typedef unsigned int XMen_SmallType;
typedef unsigned XMen_DltType XMen_LargeType;

/*Internal struct data type.*/
struct bigtype
{
    unsigned int len;
    XMen_SmallType *w;
};
typedef struct bigtype *XMen_BigTPtr;

/* Elliptical curve point structure (X, Y, Z) . */
typedef struct
{
    int marker;
    XMen_BigTPtr X;
    XMen_BigTPtr Y;
    XMen_BigTPtr Z;
} XMen_ECurvePointT;

typedef struct
{
    char *p;
    char *a;
    char *b;
    char *n;
    char *x;
    char *y;
} XMen_FP_EccT;

/* chinese remainder theorem structures. */
typedef struct
{
    XMen_BigTPtr *C;
    XMen_BigTPtr *V;
    XMen_BigTPtr *M;
    int NP;
} XMen_BigChineseT;

typedef struct
{
    int *C;
    int *V;
    int *M;
    int NP;
} XMen_SmallChineseT;

typedef XMen_BigTPtr flash;

union doubleword
{
    XMen_LargeType d;
    XMen_SmallType h[2];
};

typedef struct
{
    XMen_SmallType base; /* number base     */
    XMen_SmallType base_mask;
    XMen_SmallType apbase; /* apparent base   */
    int pack;              /* packing density */
    int lg2b;              /* bits in base    */
    XMen_SmallType base2;  /* 2^xmen_lg2b          */
    BOOL(*user)
    (void); /* pointer to user supplied function */

    int nib;    /* length of bigs  */
    BOOL check; /* overflow check  */
    BOOL fout;  /* Output to file   */
    BOOL fin;   /* Input from file  */
    BOOL active;

#ifndef XMEN_NO_RAND
    unsigned int ira[NK]; /* random number...   */
    int rndptr;           /* ...array & pointer */
    unsigned int borrow;
#endif
    /* Montgomery constants */
    XMen_SmallType ndash;
    XMen_BigTPtr modulus;
    XMen_BigTPtr pR;
    BOOL ACTIVE;
    BOOL MONTY;

    /* Elliptic Curve details   */
#ifndef XMEN_NO_SS
    BOOL SS; /* True for Super-Singular  */
#endif
#ifndef XMEN_NOKOBLITZ
    BOOL KOBLITZ; /* True for a Koblitz curve */
#endif
    int coord;
    int Asize, Bsize;
    int M, AA, BB, CC; /* for GF(2^m) curves */

#ifndef XMEN_STATIC
    int logN; /* constants for fast fourier fft multiplication */
    int nprimes, degree;
    int *prime, *cr;
    int *inverse, **roots;
    XMen_SmallChineseT chin;
    int const1, const2, const3;
    XMen_SmallType msw, lsw;
    int **s1, **s2; /* pre-computed tables for polynomial reduction */
    int **t;        /* workspace */
    int *wa;
    int *wb;
    int *wc;
#endif

    BOOL same;
    BOOL first_one;
    BOOL debug;

    XMen_BigTPtr w0; /* workspace bigs  */
    XMen_BigTPtr w1, w2, w3, w4;
    XMen_BigTPtr w5, w6, w7;
    XMen_BigTPtr w8, w9, w10, w11;
    XMen_BigTPtr w12, w13, w14, w15;
    XMen_BigTPtr sru;
    XMen_BigTPtr one;
    XMen_BigTPtr A, B;

    /* User modifiables */

#ifndef XMEN_SIMPLE_IO
    int IOBSIZ; /* size of i/o buffer */
#endif
    BOOL ERCON; /* error control   */
    int ERNUM;  /* last error code */
    int NTRY;   /* no. of tries for probablistic primality testing   */
#ifndef XMEN_SIMPLE_BASE
#ifndef XMEN_SIMPLE_IO
    int IOBASE; /* base for input and output */
    int INPLEN; /* input length               */
#endif
#endif

#ifdef XMEN_STATIC
    const int *PRIMES; /* small primes array         */
#ifndef XMEN_SIMPLE_IO
    char IOBUFF[XMEN_DEFAULT_BUFFER_SIZE]; /* i/o buffer    */
#endif
#else
    int *PRIMES; /* small primes array         */
#ifndef XMEN_SIMPLE_IO
    char *IOBUFF; /* i/o buffer    */
#endif
#endif

#ifdef XMEN_FLASH
    int workprec;
    int stprec; /* start precision */

    int RS, RD;
    double D;

    double db, n, p;
    int a, b, c, d, r, q, oldn, ndig;
    XMen_SmallType u, v, ku, kv;

    BOOL last, carryon;
    flash pi;

#endif

#ifdef XMEN_FP_ROUNDING
    XMen_LargeType inverse_base;
#endif

#ifndef XMEN_STATIC
    char *workspace;
#else
    char workspace[XMEN_BIG_RESERVE(XMEN_SPACES)];
#endif

    int TWIST; /* set to twisted curve */
    int qnr;   /* a QNR -1 for p=3 mod 4, -2 for p=5 mod 8, 0 otherwise */
    int cnr;   /* a cubic non-residue */
    int pmod8;
    int pmod9;
    BOOL NO_CARRY;
} XMen_SM2Type;

/*------------------------------Commond Data Define.------------------------------*/
#ifdef XMEN_FLASH
int workprec;
int stprec; /* start precision */

double D;

double db, n, p;
int a, b, c, d, r, q, oldn, ndig;
XMen_SmallType u, v, ku, kv;

BOOL last, carryon;
flash pi;
#endif /*XMEN_FLASH*/

/*------------------------------Internal function declaration.------------------------------*/
void XMen_Bytes2Big(int len, const char *ptr, XMen_BigTPtr x);
int XMen_Big2Bytes(int max, XMen_BigTPtr x, char *ptr, BOOL justify);
void XMen_Add(XMen_BigTPtr x, XMen_BigTPtr y, XMen_BigTPtr z);
void XMen_Multiply(XMen_BigTPtr x, XMen_BigTPtr y, XMen_BigTPtr z);
void XMen_Divide(XMen_BigTPtr x, XMen_BigTPtr y, XMen_BigTPtr z);
void XMen_Irand(unsigned int seed);
void XMen_BigRand(XMen_BigTPtr w, XMen_BigTPtr x);
void XMen_EcurveInit(XMen_BigTPtr a, XMen_BigTPtr b, XMen_BigTPtr p, int type);
int XMen_EcurveMult(XMen_BigTPtr e, XMen_ECurvePointT *pa, XMen_ECurvePointT *pt);
void XMen_EcurveMult2(XMen_BigTPtr e, XMen_ECurvePointT *p, XMen_BigTPtr ea, XMen_ECurvePointT *pa, XMen_ECurvePointT *pt);
void XMen_EpointFree(XMen_ECurvePointT *p);
XMen_ECurvePointT *XMen_EpointInit(void);
BOOL XMen_EpointSet(XMen_BigTPtr x, XMen_BigTPtr y, int cb, XMen_ECurvePointT *p);
int XMen_EpointGet(XMen_ECurvePointT *p, XMen_BigTPtr x, XMen_BigTPtr y);
XMen_SM2Type *XMen_Mirsys(int nd, XMen_SmallType nb);
flash XMen_Mirvar(int iv);
void XMen_Mirkill(XMen_BigTPtr x);
void XMen_Mirexit(void);
int XMen_Cinstr(flash x, char *string);
void XMen_Incr(XMen_BigTPtr x, int n, XMen_BigTPtr z);
int XMen_Xgcd(XMen_BigTPtr x, XMen_BigTPtr y, XMen_BigTPtr xd, XMen_BigTPtr yd, XMen_BigTPtr z);
void XMen_Subtract(XMen_BigTPtr x, XMen_BigTPtr y, XMen_BigTPtr z);
void XMen_Mad(XMen_BigTPtr x, XMen_BigTPtr y, XMen_BigTPtr z, XMen_BigTPtr w, XMen_BigTPtr q, XMen_BigTPtr r);
int XMen_Compare(XMen_BigTPtr x, XMen_BigTPtr y);
#endif /*XMEN_SM2_INTERNAL_H*/